<template>
  <div class="max-w-4xl mx-auto p-6">
    <div class="flex items-start justify-between">
      <div>
        <h1 class="text-2xl font-semibold">图片加水印（Watermark）</h1>
        <p class="mt-2 text-gray-600">在本地图片上添加文字或图片水印，实时预览并导出结果（客户端完成）。</p>
      </div>
      <NuxtLink to="/image-tools" class="text-blue-500">返回图片工具</NuxtLink>
    </div>

    <div class="mt-6 grid grid-cols-1 md:grid-cols-2 gap-6">
      <!-- Controls -->
      <div class="space-y-4">
        <label class="block">
          <div class="text-sm font-medium">主图片</div>
          <input type="file" accept="image/*" @change="onBaseSelected" class="mt-2" />
        </label>

        <div class="border rounded p-4">
          <div class="flex items-center gap-4">
            <label class="inline-flex items-center">
              <input type="radio" value="text" v-model="mode" class="mr-2" /> 文字水印
            </label>
            <label class="inline-flex items-center">
              <input type="radio" value="image" v-model="mode" class="mr-2" /> 图片水印
            </label>
          </div>

          <div v-if="mode === 'text'" class="mt-4 space-y-3">
            <label class="block">
              <div class="text-sm">水印文字</div>
              <input v-model="opts.text" class="w-full mt-1 input" placeholder="在此输入水印文字" />
            </label>
            <div class="flex gap-2">
              <label class="flex-1">
                <div class="text-sm">字体大小 (px)</div>
                <input type="range" min="10" max="120" v-model.number="opts.fontSize" />
              </label>
              <label class="w-24">
                <div class="text-sm">颜色</div>
                <input type="color" v-model="opts.color" class="w-full h-8 p-0" />
              </label>
            </div>
            <label>
              <div class="text-sm">透明度：{{ Math.round(opts.opacity * 100) }}%</div>
              <input type="range" min="0" max="100" v-model.number="tmpOpacity" />
            </label>
          </div>

          <div v-else class="mt-4 space-y-3">
            <label>
              <div class="text-sm">水印图片</div>
              <input type="file" accept="image/*" @change="onWmSelected" class="mt-2" />
            </label>
            <label>
              <div class="text-sm">缩放 (相对于主图宽度)</div>
              <input type="range" min="0.05" max="0.9" step="0.01" v-model.number="opts.wmScale" />
            </label>
            <label>
              <div class="text-sm">透明度：{{ Math.round(opts.wmOpacity * 100) }}%</div>
              <input type="range" min="0" max="100" v-model.number="tmpWmOpacity" />
            </label>
          </div>

          <div class="mt-3">
            <div class="text-sm">位置</div>
            <select v-model="opts.position" class="mt-1 input w-full">
              <option value="top-left">左上</option>
              <option value="top-right">右上</option>
              <option value="center">中间</option>
              <option value="bottom-left">左下</option>
              <option value="bottom-right">右下</option>
            </select>
          </div>
        </div>

        <div class="flex gap-3">
          <button @click="downloadImage" :disabled="!canExport" class="btn btn-primary" >导出图片</button>
          <button @click="resetAll" class="btn">重置</button>
        </div>
      </div>

      <!-- Preview -->
      <div>
        <div class="border rounded p-4">
          <div class="text-sm text-gray-600">预览（画布）</div>
          <div class="mt-3 flex items-center justify-center bg-gray-50" style="min-height:240px">
            <canvas ref="canvasRef" class="max-w-full max-h-[60vh]" />
            <div v-if="!baseImg" class="text-gray-400">请先上传主图片以查看预览</div>
          </div>
        </div>
        <div class="mt-3 text-xs text-gray-500">提示：导出会生成 PNG（保留透明通道）。</div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive, watch, onMounted, computed } from 'vue'
useHead({ title: '图片加水印 - 图片工具' })

const canvasRef = ref(null)

// 主图
const baseFile = ref(null)
const baseUrl = ref(null)
const baseImg = ref(null)

// 水印图片
const wmFile = ref(null)
const wmUrl = ref(null)
const wmImg = ref(null)

const mode = ref('text')

const opts = reactive({
  // 文本水印
  text: '示例水印',
  fontSize: 36,
  color: '#ffffff',
  opacity: 0.5,
  // 图片水印
  wmScale: 0.2, // 相对于主图宽度的比例
  wmOpacity: 0.5,
  // 通用
  position: 'bottom-right'
})

// 临时滑块绑定（因为 input range 使用整数更顺畅）
const tmpOpacity = ref(Math.round(opts.opacity * 100))
const tmpWmOpacity = ref(Math.round(opts.wmOpacity * 100))

watch(tmpOpacity, v => { opts.opacity = (v/100) })
watch(tmpWmOpacity, v => { opts.wmOpacity = (v/100) })

function onBaseSelected(e) {
  const f = e.target.files && e.target.files[0]
  if (!f) return
  baseFile.value = f
  const reader = new FileReader()
  reader.onload = ev => {
    baseUrl.value = ev.target.result
    const img = new Image()
    img.onload = () => {
      baseImg.value = img
      draw()
    }
    img.src = ev.target.result
  }
  reader.readAsDataURL(f)
}

function onWmSelected(e) {
  const f = e.target.files && e.target.files[0]
  if (!f) return
  wmFile.value = f
  const reader = new FileReader()
  reader.onload = ev => {
    wmUrl.value = ev.target.result
    const img = new Image()
    img.onload = () => {
      wmImg.value = img
      draw()
    }
    img.src = ev.target.result
  }
  reader.readAsDataURL(f)
}

function clearCanvas(ctx, w, h) {
  ctx.clearRect(0,0,w,h)
}

function draw() {
  const canvas = canvasRef.value
  const ctx = canvas && canvas.getContext && canvas.getContext('2d')
  if (!canvas || !ctx) return
  if (!baseImg.value) {
    // 清空并显示占位
    canvas.width = 600
    canvas.height = 360
    ctx.fillStyle = '#f8fafc'
    ctx.fillRect(0,0,canvas.width, canvas.height)
    return
  }

  // 设置 canvas 大小为主图原始尺寸（如过大则按比例缩放以避免浏览器卡顿）
  const maxDim = 1600
  let w = baseImg.value.naturalWidth || baseImg.value.width
  let h = baseImg.value.naturalHeight || baseImg.value.height
  let scale = 1
  if (w > maxDim) {
    scale = maxDim / w
    w = Math.round(w * scale)
    h = Math.round(h * scale)
  }

  // 处理高 DPI 展示
  const dpr = window.devicePixelRatio || 1
  canvas.width = Math.round(w * dpr)
  canvas.height = Math.round(h * dpr)
  canvas.style.width = w + 'px'
  canvas.style.height = h + 'px'
  ctx.setTransform(dpr, 0, 0, dpr, 0, 0)

  // 绘制主图
  ctx.drawImage(baseImg.value, 0, 0, w, h)

  // 绘制水印
  if (mode.value === 'text' && opts.text) {
    ctx.save()
    ctx.globalAlpha = opts.opacity
    ctx.fillStyle = opts.color
    const fontSize = opts.fontSize * (w / (baseImg.value.naturalWidth || baseImg.value.width))
    ctx.font = `${fontSize}px sans-serif`
    ctx.textBaseline = 'middle'
    ctx.textAlign = 'left'
    const text = opts.text
    const metrics = ctx.measureText(text)
    const tw = metrics.width
    const th = fontSize
    const { x, y } = computePosition(opts.position, w, h, tw, th)
    // 加一点阴影以提高可读性
    ctx.shadowColor = 'rgba(0,0,0,0.4)'
    ctx.shadowBlur = Math.max(2, fontSize * 0.08)
    ctx.fillText(text, x, y)
    ctx.restore()
  }

  if (mode.value === 'image' && wmImg.value) {
    ctx.save()
    ctx.globalAlpha = opts.wmOpacity
    // 根据比例计算水印尺寸
    const targetW = Math.round(w * opts.wmScale)
    const targetH = Math.round((wmImg.value.naturalHeight || wmImg.value.height) * (targetW / (wmImg.value.naturalWidth || wmImg.value.width)))
    const { x, y } = computePosition(opts.position, w, h, targetW, targetH)
    ctx.drawImage(wmImg.value, x, y, targetW, targetH)
    ctx.restore()
  }
}

function computePosition(pos, containerW, containerH, itemW, itemH) {
  const margin = Math.round(Math.min(containerW, containerH) * 0.04)
  let x = 0, y = 0
  switch (pos) {
    case 'top-left':
      x = margin; y = margin + itemH/2
      break
    case 'top-right':
      x = containerW - itemW - margin; y = margin + itemH/2
      break
    case 'center':
      x = Math.round((containerW - itemW)/2); y = Math.round(containerH/2)
      break
    case 'bottom-left':
      x = margin; y = containerH - margin - itemH/2
      break
    case 'bottom-right':
    default:
      x = containerW - itemW - margin; y = containerH - margin - itemH/2
      break
  }
  return { x, y }
}

const canExport = computed(() => !!baseImg.value)

function downloadImage() {
  if (!canExport.value) return
  const canvas = canvasRef.value
  // 默认导出 PNG
  const data = canvas.toDataURL('image/png')
  const a = document.createElement('a')
  a.href = data
  a.download = 'watermark.png'
  document.body.appendChild(a)
  a.click()
  a.remove()
}

function resetAll() {
  baseFile.value = null
  baseUrl.value = null
  baseImg.value = null
  wmFile.value = null
  wmUrl.value = null
  wmImg.value = null
  opts.text = '示例水印'
  opts.fontSize = 36
  opts.color = '#ffffff'
  opts.opacity = 0.5
  opts.wmScale = 0.2
  opts.wmOpacity = 0.5
  tmpOpacity.value = Math.round(opts.opacity * 100)
  tmpWmOpacity.value = Math.round(opts.wmOpacity * 100)
  // clear canvas
  draw()
}

// 当选项变化时，重新绘制
watch([() => mode.value, () => opts.position, () => opts.text, () => opts.fontSize, () => opts.color, () => opts.wmScale, () => opts.wmOpacity, () => opts.opacity], draw)

onMounted(() => {
  // 初始绘制空白画布
  draw()
})
</script>

<style scoped>
.input {
  border: 1px solid #e5e7eb;
  border-radius: 0.375rem;
  padding: 0.25rem 0.5rem;
}
.btn {
  border: 1px solid #e5e7eb;
  border-radius: 0.375rem;
  padding: 0.5rem 0.75rem;
  background: #fff;
}
.btn-primary {
  background: #3b82f6; /* blue-500 */
  color: #fff;
  border-color: #3b82f6;
}
</style>
